#ifndef CAN_OPEN_DRIVER_H
#define CAN_OPEN_DRIVER_H

#include <fcntl.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <unistd.h>

#include <atomic>
#include <cstring>
#include <iostream>
#include <mutex>

class CANopenDriver {
 public:
  CANopenDriver(std::string interface, int bitrate);

  ~CANopenDriver();

  bool sendFrame(const can_frame& frame);

  bool receiveFrame(can_frame& frame, int timeout_ms = 1000);

  void sdoDownload(uint8_t node_id, uint16_t index, uint8_t subindex,
                   uint32_t data, uint8_t size);

  void sdoUpload(uint8_t node_id, uint16_t index, uint8_t subindex,
                 uint32_t& data, uint8_t& size);

  void sendPDO1(uint8_t pdo_num, const uint8_t* data, uint8_t size);

  void sendPDO2(uint8_t pdo_num, const uint8_t* data, uint8_t size);

  void receivePDO1(uint8_t pdo_num, uint8_t* data, int timeout_ms = 1000);

  void sendHeartBeat(uint8_t node_id);

  bool isCanDriverRunning();

 private:
  int m_sockfd;
  struct sockaddr_can m_addr;
  struct ifreq m_ifr;
  std::string m_ifname;
  std::mutex m_mtx;
  std::atomic<uint32_t> m_errCounts{0};
  static std::atomic<bool> m_runningState;
};

#endif